package com.lanyou.esb.service;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.transaction.Transactional;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import redis.clients.jedis.exceptions.JedisException;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.lanyou.cook.datadictionary.UserLogOpt;
import com.lanyou.cook.service.UserLogService;
import com.lanyou.esb.common.CommonUtils;
import com.lanyou.esb.entity.Http;
import com.lanyou.esb.entity.IfReqQuantity;
import com.lanyou.esb.exception.QuantityControlException;
import com.lanyou.esb.redis.proxy.impl.IfReqQuantityJedisProxy;
import com.lanyou.esb.redis.vo.IfReqQuantityVo;
import com.lanyou.esb.repository.IfReqQuantityRepository;
import com.lanyou.esb.web.param.HttpInterfaceParam;
import com.lanyou.esb.web.param.InterfaceRequestQuantityParam;
import com.lanyou.esb.web.quantityControlcontrol.vo.QuantityControlVo;

/**
 * 流量控制<br>
 * 
 * 
 * @author Davey.wu
 */
@Service
public class QuantityControlService {
	@PersistenceContext
	private EntityManager entityManager;
	@Autowired
	IfReqQuantityRepository interfaceRequestQuantityRepository;

	@Autowired
	private IfReqQuantityJedisProxy ifReqQuantityJedisProxy;

	@Autowired
	private UserLogService userLogService;

	/**
	 * 更新流量控制信息
	 * 
	 * @param param
	 * @throws QuantityControlException
	 */
	@Transactional
	public void updateQuantity(InterfaceRequestQuantityParam param)
			throws QuantityControlException {
		String requestThreshold = param.getRequestThreshold();
		String requestMax = param.getRequestMax();
		int threshold = 0;
		int max = 0;
		try {
			threshold = Integer.parseInt(requestThreshold);
			if (threshold < 0) {
				throw new QuantityControlException(
						"请求阀值只能是正整数,最大值为【999999999】！", 0);
			}
		} catch (Exception e) {
			throw new QuantityControlException("请求阀值只能是正整数,最大值为【999999999】！", 0);
		}
		try {
			max = Integer.parseInt(requestMax);
			if (max < 0) {
				throw new QuantityControlException(
						"请求最大值只能是正整数,最大值为【999999999】！", 0);
			}
		} catch (Exception e) {
			throw new QuantityControlException("请求最大值只能是正整数,最大值为【999999999】！",
					0);
		}
		if (threshold > max) {
			throw new QuantityControlException(
					"请求阀值不能超过请求最大值,最大值为【999999999】！", 0);
		}
		IfReqQuantity ifReqtQuantity = interfaceRequestQuantityRepository
				.findOne(IfReqQuantity.idSpecification(param.getId()));
		if (ifReqtQuantity == null) {
			throw new QuantityControlException("找不到相应ID的流量控制信息", 0);
		}
		Http http = ifReqtQuantity.getHttp();
		if (http == null) {
			throw new QuantityControlException("找不到与流量控制相关的的HTTP接口信息！", 0);
		}
		ifReqtQuantity.setRequestThreshold(param.getRequestThreshold());
		ifReqtQuantity.setRequestMax(param.getRequestMax());
		List<IfReqQuantity> list = new ArrayList<>(0);
		list.add(ifReqtQuantity);
		interfaceRequestQuantityRepository.save(list);
		// 更新流量阀值和最大值同步更新redis的数据
		updateIfReqQuantityRedisData(list);

		userLogService.save(UserLogOpt.MaintenanceQuantityControl, null,
				String.format("更新接口“%s”的流量控制信息", http.getName()));
	}

	/**
	 * 获取流量控制
	 * 
	 * @param param
	 *            ：查询条件
	 * @param pageable
	 *            ：分页条件
	 * @param userId
	 * @return
	 */
	public Page<QuantityControlVo> findRequestQuantity(
			HttpInterfaceParam param, Pageable pageable, String userId) {
		// 获取总记录数
		BigInteger total = getReqQuantityTotal(param, userId);
		// 存在符合条件的记录，则取记录
		if (total == null || total.longValue() <= 0) {
			return new PageImpl<QuantityControlVo>(
					new ArrayList<QuantityControlVo>(0), pageable, 0);
		}
		// 获取记录
		List<Object[]> objects = getReqQuantity(param, pageable, userId);
		List<QuantityControlVo> result = new ArrayList<>(objects.size());
		// 转换结果集
		for (Object[] object : objects) {
			QuantityControlVo vo = new QuantityControlVo();
			vo.setName(object[0] != null ? (String) object[0] : "");
			vo.setStatus(object[1] != null ? (String) object[1] : "");
			vo.setFieldName(object[2] != null ? (String) object[2] : "");
			vo.setFieldSystemName(object[3] != null ? (String) object[3] : "");

			vo.setQuantityId(object[4] != null ? (String) object[4] : "");
			vo.setRequestThreshold(object[5] != null ? (int) object[5] : 0);
			vo.setRequestMax(object[6] != null ? (int) object[6] : 0);
			result.add(vo);
		}
		Page<QuantityControlVo> page = new PageImpl<QuantityControlVo>(result,
				pageable, total.longValue());
		return page;
	}

	/**
	 * 获取流量控制
	 * 
	 * @param param
	 *            ：查询条件
	 * @param pageable
	 *            ：分页对象
	 * @param userId
	 * @return
	 */
	private List<Object[]> getReqQuantity(HttpInterfaceParam param,
			Pageable pageable, String userId) {
		String sql = "SELECT "
				+ "V0.IF_NAME, "
				+ "V0.IF_STATUS, "
				+ "(SELECT f.FIELD_NAME FROM t_cook_bu_field_system s,t_cook_db_field f WHERE V0.FIELD_SYSTEM_ID=s.FIELD_SYSTEM_ID AND s.FIELD_ID=f.FIELD_ID ) AS fieldName, "
				+ "(SELECT s.SYSTEM_NAME FROM t_cook_bu_field_system s WHERE s.FIELD_SYSTEM_ID=V0.FIELD_SYSTEM_ID) AS systemName, "
				+ "(SELECT q.IF_REQUEST_QTY_ID FROM t_esb_bu_if_request_qty q WHERE V0.IF_HTTP_ID=q.IF_ID AND q.REQUEST_UNIT='3') AS qytId, "
				+ "(SELECT q.REQUEST_THRESHOLD FROM t_esb_bu_if_request_qty q WHERE V0.IF_HTTP_ID=q.IF_ID AND q.REQUEST_UNIT='3') AS threshold, "
				+ "(SELECT q.MAX_REQUEST_QTY FROM t_esb_bu_if_request_qty q WHERE V0.IF_HTTP_ID=q.IF_ID AND q.REQUEST_UNIT='3') AS maxQty "

				+ "FROM "
				+ "	(SELECT h.IF_HTTP_ID,h.IF_NAME,h.IF_STATUS,h.FIELD_SYSTEM_ID FROM t_esb_bu_if_http h "
				+ "	WHERE " + "	h.IS_ENABLE='1'  ";
		// 添加接口名称条件
		if (StringUtils.isNotBlank(param.getName())) {
			sql += "AND h.IF_NAME LIKE :ifName ";
		}
		// 添加系统标识条件
		if (StringUtils.isNotBlank(param.getFieldSystemId())) {
			sql += "AND h.FIELD_SYSTEM_ID=:systemId  ";
		}
		// 添加领域标识条件
		if (StringUtils.isNotBlank(param.getFieldId())) {
			sql += "AND EXISTS(SELECT f.FIELD_ID FROM t_cook_bu_field_system s, t_cook_db_field f WHERE h.FIELD_SYSTEM_ID=s.FIELD_SYSTEM_ID AND s.FIELD_ID=f.FIELD_ID AND f.FIELD_ID=:fieldId ) ";
		}
		sql += "AND EXISTS( "
				+ "			SELECT U0.FIELD_SYSTEM_ID  "
				+ "			FROM t_cook_bu_user_system U0  "
				+ "			WHERE h.FIELD_SYSTEM_ID=U0.FIELD_SYSTEM_ID AND U0.USER_ID=:userId) "
				+ "	LIMIT :pageNumber,:pageSize " + ")AS V0";

		Query query = entityManager.createNativeQuery(sql);

		// 添加接口名称参数
		if (StringUtils.isNotBlank(param.getName())) {
			query.setParameter("ifName", param.getName());
		}
		// 添加系统标识参数
		if (StringUtils.isNotBlank(param.getFieldSystemId())) {
			query.setParameter("systemId", param.getFieldSystemId());
		}
		// 添加领域标识参数
		if (StringUtils.isNotBlank(param.getFieldId())) {
			query.setParameter("fieldId", param.getFieldId());
		}
		query.setParameter("userId", userId);
		query.setParameter("pageNumber",
				pageable.getPageNumber() * pageable.getPageSize());
		query.setParameter("pageSize", pageable.getPageSize());
		// 获取结果集
		List<Object[]> rows = query.getResultList();
		return rows;
	}

	/**
	 * 获取流量控制总记录数
	 * 
	 * @param param
	 * @param userId
	 * @return
	 */
	private BigInteger getReqQuantityTotal(HttpInterfaceParam param,
			String userId) {
		String sql = "	SELECT COUNT(h.IF_HTTP_ID) AS total FROM t_esb_bu_if_http h "
				+ "	WHERE " + "	h.IS_ENABLE='1'  ";
		// 添加接口名称条件
		if (StringUtils.isNotBlank(param.getName())) {
			sql += "AND h.IF_NAME LIKE :ifName ";
		}
		// 添加系统标识条件
		if (StringUtils.isNotBlank(param.getFieldSystemId())) {
			sql += "AND h.FIELD_SYSTEM_ID=:systemId  ";
		}
		// 添加领域标识条件
		if (StringUtils.isNotBlank(param.getFieldId())) {
			sql += "AND EXISTS(SELECT f.FIELD_ID FROM t_cook_bu_field_system s, t_cook_db_field f WHERE h.FIELD_SYSTEM_ID=s.FIELD_SYSTEM_ID AND s.FIELD_ID=f.FIELD_ID AND f.FIELD_ID=:fieldId ) ";
		}
		sql += "AND EXISTS( "
				+ "			SELECT U0.FIELD_SYSTEM_ID  "
				+ "			FROM t_cook_bu_user_system U0  "
				+ "			WHERE h.FIELD_SYSTEM_ID=U0.FIELD_SYSTEM_ID AND U0.USER_ID=:userId) ";

		Query query = entityManager.createNativeQuery(sql);

		// 添加接口名称参数
		if (StringUtils.isNotBlank(param.getName())) {
			query.setParameter("ifName", param.getName());
		}
		// 添加系统标识参数
		if (StringUtils.isNotBlank(param.getFieldSystemId())) {
			query.setParameter("systemId", param.getFieldSystemId());
		}
		// 添加领域标识参数
		if (StringUtils.isNotBlank(param.getFieldId())) {
			query.setParameter("fieldId", param.getFieldId());
		}
		query.setParameter("userId", userId);
		// 获取记录
		List rows = query.getResultList();
		if (rows == null || rows.isEmpty()) {
			return new BigInteger("0");
		}
		BigInteger total = (BigInteger) rows.get(0);
		return (BigInteger) total;
	}

	/**
	 * 新增或修改Redis中对应数据类
	 * 
	 * @param ifReqQuantitys
	 * @throws QuantityControlException
	 */
	private void updateIfReqQuantityRedisData(List<IfReqQuantity> ifReqQuantitys)
			throws QuantityControlException {
		try {
			for (IfReqQuantity ifReqQuantity : ifReqQuantitys) {
				IfReqQuantityVo target = IfReqQuantityVo
						.getInstance(ifReqQuantity);
				ifReqQuantityJedisProxy.hset(
						ifReqQuantityJedisProxy.generateKeyFromObject(target),
						target);
			}
		} catch (JsonProcessingException e) {
			throw new QuantityControlException(
					CommonUtils.MSG_JSON_PARSING_ERROR,
					CommonUtils.CODE_JSON_PARSING_ERROR);
		} catch (JedisException e) {
			throw new QuantityControlException(
					CommonUtils.MSG_CONNECT_REDIS_FAIED,
					CommonUtils.CODE_CONNECT_REDIS_FAIED);
		} catch (Exception e) {
			throw new QuantityControlException(
					CommonUtils.MSG_UPDATE_REDIS_DATA_FAIED,
					CommonUtils.CODE_UPDATE_REDIS_DATA_FAIED);
		}
	}
}
